package com.ruike.alisurface.broadcastReceiver;

import android.annotation.SuppressLint;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.telephony.PhoneStateListener;
import android.telephony.SignalStrength;
import android.telephony.TelephonyManager;

import com.voodoo.lib_logcat.L;

import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Enumeration;

/**
 * Author：voodoo
 * CreateTime：2021/07/02 002 上午 09:24
 * Description：网络改变监听
 * <p>
 * // 动态注册网络的广播监听
 * NetworkReceiver networkChangedReceiver = new NetworkReceiver();
 * networkChangedReceiver.setOnNetworkChangeListener(new NetworkReceiver.OnNetworkChangeListener() {
 *
 * @Override public void onNetworkChange(boolean isConnect, NetworkReceiver.NetworkType networkType, int signalStrength, NetworkReceiver.NetworkLevel level) {
 * }
 * });
 * IntentFilter intentFilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
 * registerReceiver(networkChangedReceiver, intentFilter);
 * <p>
 * // 记得解注册
 * unregisterReceiver(networkChangedReceiver);
 */
public class NetWorkBroadcastReceiver extends BroadcastReceiver {

    private static final String TAG = "NetworkReceiver";

    Handler mainHandler;
    private PhoneStatListener phoneStatListener;

    public enum NetworkType {
        // 无网络     WIFI       移动网络       以太网          未知
        TYPE_NONE, TYPE_WIFI, TYPE_MOBILE, TYPE_ETHERNET, TYPE_UNKNOW
    }

    public enum NetworkLevel {
        LEVEL_0, // 正常连接的情况下是：连接了，但是基本上没网，无法上网的状态
        LEVEL_1, // 网络微弱的状态
        LEVEL_2, // 网络比较弱
        LEVEL_3, // 网络微强
        LEVEL_4,  // 网络接近满格
        LEVEL_10  // 网线
    }

    @Override
    public void onReceive(Context context, Intent intent) {

        ConnectivityManager connectivityManager = (ConnectivityManager) context.getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
        if (networkInfo != null) {
//            NetworkInfo: type: ETHERNET[], state: CONNECTED/CONNECTED, reason: (unspecified), extra: (none), roaming: false, failover: false, isAvailable: true, isConnectedToProvisioningNetwork: false
            if (networkInfo.isConnected()) {

                // 判断网络类型
                switch (networkInfo.getType()) {
                    case ConnectivityManager.TYPE_WIFI: // WIFI
                        getWifiInfo(context);
                        break;
                    case ConnectivityManager.TYPE_ETHERNET: // 以太网（网线）
                        getEthernetInfo(intent);
                        break;
                    case ConnectivityManager.TYPE_MOBILE: // 4G卡
                        if (mainHandler == null) {
                            mainHandler = new Handler(Looper.getMainLooper());
                        }
                        mainHandler.post(new Runnable() {
                            @Override
                            public void run() {
                                phoneStatListener = new PhoneStatListener();
                                getMobileInfo(context);
                            }
                        });
                        break;
                    default:
                        L.iTag(TAG, "网络类型：" + NetworkType.TYPE_UNKNOW);
                        if (onNetworkChangeListener != null) {
                            onNetworkChangeListener.onNetworkChange(true, NetworkType.TYPE_UNKNOW, 0, NetworkLevel.LEVEL_0);
                        }
                        break;
                }
            } else {
                L.iTag(TAG, "网络断开");
                if (onNetworkChangeListener != null) {
                    onNetworkChangeListener.onNetworkChange(false, NetworkType.TYPE_NONE, 0, NetworkLevel.LEVEL_0);
                }
            }
        } else {
            L.iTag(TAG, "NetworkInfo为空，当前网络不可用");
            if (onNetworkChangeListener != null) {
                onNetworkChangeListener.onNetworkChange(false, NetworkType.TYPE_NONE, 0, NetworkLevel.LEVEL_0);
            }
        }

    }

    // ======================================================================================== WIFI

    /**
     * 获取WIFI的具体信息
     * Level：
     * (-∞，-85)  0
     * [-85, -70)  1
     * [-70, -55)  2
     * [-55, +∞)  3
     * wifiManager.calculateSignalLevel(sr.level, 4); // 计算公式
     *
     * @param context 上下文
     */
    private void getWifiInfo(Context context) {
        // SSID: CU_RK, BSSID: f4:b5:aa:7b:f6:dc, MAC: 02:00:00:00:00:00, Supplicant state: COMPLETED, RSSI: -29, Link speed: 72Mbps, Frequency: 2422MHz, Net ID: 0, Metered hint: false, score: 60
        WifiManager wifiManager = (WifiManager) context.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
        WifiInfo wifiInfo = wifiManager.getConnectionInfo();

        NetworkLevel networkLevel;
        switch (WifiManager.calculateSignalLevel(wifiInfo.getRssi(), 5)) {
            case 4:
                networkLevel = NetworkLevel.LEVEL_4;
                break;
            case 3:
                networkLevel = NetworkLevel.LEVEL_3;
                break;
            case 2:
                networkLevel = NetworkLevel.LEVEL_2;
                break;
            case 1:
                networkLevel = NetworkLevel.LEVEL_1;
                break;
            default:
                networkLevel = NetworkLevel.LEVEL_0;
                break;
        }

        if (onNetworkChangeListener != null) {
            onNetworkChangeListener.onNetworkChange(true, NetworkType.TYPE_WIFI, wifiInfo.getRssi(), networkLevel);
        }

        // 需要的回调完成，以下全是为了打印出来获取的信息

        // 获取IP地址（内网的）
        int ipAddress = wifiInfo.getIpAddress();
        StringBuilder ipAddressBuilder = new StringBuilder();
        ipAddressBuilder.append(ipAddress & 0xFF).append(".");
        ipAddressBuilder.append((ipAddress >> 8) & 0xFF).append(".");
        ipAddressBuilder.append((ipAddress >> 16) & 0xFF).append(".");
        ipAddressBuilder.append((ipAddress >> 24) & 0xFF);

        @SuppressLint("HardwareIds")
        String stringFormat = String.format("网络类型 WIFI\nSSID: %s\nBSSID: %s\nMacAddress: %s(%s)\nSupplicantState: %s\nRssi: %s\nLinkSpeed: %sMbps\nIpAddress: %s\nLevel:%s",
                wifiInfo.getSSID(), wifiInfo.getBSSID().toUpperCase(), getMacAddress(), // Attempt to get length of null array
                wifiInfo.getMacAddress(), wifiInfo.getSupplicantState(), wifiInfo.getRssi(),
                wifiInfo.getLinkSpeed(), ipAddressBuilder.toString(), networkLevel);
        // 如果系统版本大于 21（Android_5.0) 则获取一下频率
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            stringFormat += String.format("\nFrequency: %.3sGHz", wifiInfo.getFrequency() / 1000.0);
        }
        L.iTag(TAG, stringFormat);

    }

    // ======================================================================================= 以太网

    /**
     * 获取以太网的具体信息
     *
     * @param intent 上下文
     */
    @SuppressLint("WrongConstant")
    private void getEthernetInfo(Intent intent) {

        Bundle bundle = intent.getExtras();
        String hostIp = "";
        try {
            Enumeration nis = NetworkInterface.getNetworkInterfaces();
            InetAddress ia = null;
            while (nis.hasMoreElements()) {
                NetworkInterface ni = (NetworkInterface) nis.nextElement();
                Enumeration<InetAddress> ias = ni.getInetAddresses();
                while (ias.hasMoreElements()) {
                    ia = ias.nextElement();
                    if (ia instanceof Inet6Address) {
                        continue;// skip ipv6
                    }
                    String ip = ia.getHostAddress();
                    if (!"127.0.0.1".equals(ip)) {
                        hostIp = ia.getHostAddress();
                        break;
                    }
                }
            }
        } catch (SocketException e) {
            L.eTag(TAG, "SocketException：" + e.toString());
        }

        int inetCondition = 100; // 信号强度，网线默认是最好的信号强度
        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) {
            inetCondition = bundle.getInt("inetCondition");
        }

        if (onNetworkChangeListener != null) {
            onNetworkChangeListener.onNetworkChange(true, NetworkType.TYPE_ETHERNET, inetCondition, NetworkLevel.LEVEL_10);
        }

        L.iTag(TAG, String.format("网络类型 以太网\n信号强度：%s\nIP地址：%s\nMac地址：%s", inetCondition, hostIp, getMacAddress()));

    }

    /**
     * 获取Mac地址
     *
     * @return Mac地址
     */
    private String getMacAddress() {
        StringBuffer buffer = null;
        try {
            Enumeration<NetworkInterface> en_netInterface = NetworkInterface.getNetworkInterfaces();
            InetAddress ipAddress = null;
            while (en_netInterface.hasMoreElements()) {
                NetworkInterface ni = en_netInterface.nextElement();
                Enumeration<InetAddress> en_ip = ni.getInetAddresses();
                while (en_ip.hasMoreElements()) {
                    ipAddress = en_ip.nextElement();
                    if (!ipAddress.isLoopbackAddress() && !ipAddress.getHostAddress().contains(":")) {
                        break;
                    } else {
                        ipAddress = null;
                    }
                }
                if (ipAddress != null) {
                    break;
                }
            }

            if (ipAddress != null) {
                buffer = new StringBuffer();
                byte[] b = NetworkInterface.getByInetAddress(ipAddress).getHardwareAddress();
                if (b != null) {
                    for (int i = 0; i < b.length; i++) {
                        if (i != 0) {
                            buffer.append('-');
                        }
                        String str = Integer.toHexString(b[i] & 0xFF);
                        buffer.append(str.length() == 1 ? 0 + str : str);
                    }
                }
                return buffer.toString().toUpperCase();
            } else {
                return "";
            }

        } catch (SocketException e) {
            L.eTag(TAG, "获取Mac地址异常：" + e.toString());
        }
        return buffer == null ? "" : buffer.toString();
    }

    // =================================================================================== 4G物联网卡

    /**
     * 获取4G网络的具体信息
     *
     * @param context 上下文
     */
    private void getMobileInfo(Context context) {
        L.iTag(TAG, "当前链接 移动网络");
        TelephonyManager telephonyManager = (TelephonyManager) context.getApplicationContext().getSystemService(Context.TELEPHONY_SERVICE);
        telephonyManager.listen(phoneStatListener, PhoneStateListener.LISTEN_SIGNAL_STRENGTHS);
    }

    @SuppressWarnings("deprecation")
    private class PhoneStatListener extends PhoneStateListener {
        @Override
        public void onSignalStrengthsChanged(SignalStrength signalStrength) {
            super.onSignalStrengthsChanged(signalStrength);
            int asu = signalStrength.getGsmSignalStrength(); // 获得的是asu值
            int dbm = -113 + 2 * asu; // dBm（1毫瓦的分贝数）和 asu（alone signal unit 独立信号单元）之间的关系是：dBm = -113 + 2 * asu
            // 简单的说dBm值肯定是负数的，越接近0信号就越好，但是不可能为0的，低于-113那就是没信号了，而ASU的值则相反，是正数，也是值越大越好

            NetworkLevel networkLevel;
            // 获取网络信号强度  获取0-4的5种信号级别，越大信号越好,但是api23开始才能用
            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
                L.iTag(TAG, "getLevel:" + signalStrength.getLevel());
                switch (signalStrength.getLevel()) {
                    case 4:
                        networkLevel = NetworkLevel.LEVEL_4;
                        break;
                    case 3:
                        networkLevel = NetworkLevel.LEVEL_3;
                        break;
                    case 2:
                        networkLevel = NetworkLevel.LEVEL_2;
                        break;
                    case 1:
                        networkLevel = NetworkLevel.LEVEL_1;
                        break;
                    default:
                        networkLevel = NetworkLevel.LEVEL_0;
                        break;
                }
            } else {
                // 参考：https://blog.csdn.net/u012251822/article/details/12157287
                // 简单的说dBm值肯定是负数的，越接近0信号就越好，但是不可能为0的，低于-113那就是没信号了。 ASU的值则相反，是正数，也是值越大越好
                // 城市里dbm大于-90，农村里大于-94就是正常的，举例说明就是：-81dBm的信号比-90dBm的强，-67dBm的信号比-71dBm的强
                if (dbm >= -50) { // 最强
                    networkLevel = NetworkLevel.LEVEL_4;
                } else if (dbm >= -70) { // 较强
                    networkLevel = NetworkLevel.LEVEL_3;
                } else if (dbm >= -80) { // 较弱
                    networkLevel = NetworkLevel.LEVEL_2;
                } else if (dbm >= -100) { // 微弱
                    networkLevel = NetworkLevel.LEVEL_1;
                } else { // 基本无网络
                    networkLevel = NetworkLevel.LEVEL_0;
                }
            }

            L.iTag(TAG, String.format("网络类型 手机卡\nasu:%s\ndbm:%s\nlevel:%s", asu, dbm, networkLevel));

            if (onNetworkChangeListener != null) {
                onNetworkChangeListener.onNetworkChange(true, NetworkType.TYPE_MOBILE, dbm, networkLevel);
            }
        }
    }

    // ======================================== 该类的接口

    public OnNetworkChangeListener onNetworkChangeListener;

    public void setOnNetworkChangeListener(OnNetworkChangeListener onNetworkChangeListener) {
        this.onNetworkChangeListener = onNetworkChangeListener;
    }

    public interface OnNetworkChangeListener {
        /**
         * 网络信号回调
         *
         * @param isConnect      是否链接
         * @param networkType    网络类型
         * @param signalStrength 信号强度
         * @param level          信号强度级别
         */
        void onNetworkChange(boolean isConnect, NetworkType networkType, int signalStrength, NetworkLevel level);
    }

}
